package com.key.win.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.key.win.base.exception.BizException;
import com.key.win.base.page.MybatisPageServiceTemplate;
import com.key.win.base.util.BeanUtils;
import com.key.win.base.util.SingleSoldierConstantUtils;
import com.key.win.base.web.PageRequest;
import com.key.win.base.web.PageResult;
import com.key.win.system.dao.SysOrganDao;
import com.key.win.system.dao.SysOrganDeviceDao;
import com.key.win.system.dao.SysOrganUserDao;
import com.key.win.system.model.SysDevice;
import com.key.win.system.model.SysOrgan;
import com.key.win.system.model.SysOrganUser;
import com.key.win.system.model.SysUser;
import com.key.win.system.service.SysOrganService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysOrganServiceImpl extends ServiceImpl<SysOrganDao, SysOrgan> implements SysOrganService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SysOrganUserDao sysOrganUserDao;

    @Autowired
    private SysOrganDeviceDao sysOrganDeviceDao;

    @Override
    public List<SysOrgan> findSysOrgan(SysOrgan sysOrgan) {
        LambdaQueryWrapper<SysOrgan> lambdaQueryWrapper = new LambdaQueryWrapper<SysOrgan>();
        if (sysOrgan != null) {
            if (StringUtils.isNotBlank(sysOrgan.getCode())) {
                lambdaQueryWrapper.eq(SysOrgan::getCode, sysOrgan.getCode());
            }
            if (StringUtils.isNotBlank(sysOrgan.getName())) {
                lambdaQueryWrapper.eq(SysOrgan::getName, sysOrgan.getName());
            }
            if (StringUtils.isNotBlank(sysOrgan.getParentId())) {
                lambdaQueryWrapper.eq(SysOrgan::getParentId, sysOrgan.getParentId());
            }
        }
        List<SysOrgan> list = this.list(lambdaQueryWrapper);
        return list;
    }

    @Override
    public List<SysOrgan> getOrganTree() {
        List<SysOrgan> list = this.list();
        List<SysOrgan> topList = new ArrayList<>();
        Map<String, SysOrgan> levelAll = new HashMap<>();
        if (!CollectionUtils.isEmpty(list)) {
            for (SysOrgan organ : list) {
                if (SingleSoldierConstantUtils.ORGAN_TREE_PARENT_ID.equals(organ.getParentId())) {
                    topList.add(organ);
                }
                levelAll.put(organ.getId(), organ);
            }
            for (Map.Entry<String, SysOrgan> entry : levelAll.entrySet()) {
                SysOrgan value = entry.getValue();
                if (!SingleSoldierConstantUtils.ORGAN_TREE_PARENT_ID.equals(value.getParentId())) {
                    String key = value.getParentId();
                    SysOrgan parentOrgan = levelAll.get(key);
                    parentOrgan.addSubSysOrgan(value);
                }
            }
        }
        /*topList.sort(new Comparator<SysOrgan>() {
            @Override
            public int compare(SysOrgan o1, SysOrgan o2) {
                if (o1.getOrder() > o2.getOrder()) {
                    return 1;
                } else if (o1.getOrder() < o2.getOrder()) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });*/
        this.organSort(topList);
        return topList;
    }

    public void organSort(List<SysOrgan> organs) {
        organs.sort((o1, o2) -> {
            if (o1.getSort() > o2.getSort()) {
                return 1;
            } else if (o1.getSort() < o2.getSort()) {
                return -1;
            } else {
                return 0;
            }
        });
        organs.forEach(organ -> {
            if (!CollectionUtils.isEmpty(organ.getSubOrgan())) {
                this.organSort(organ.getSubOrgan());
            }
        });
    }

    @Override
    public List<SysOrgan> findSysOrganByParentId(String parentId) {
        if (StringUtils.isBlank(parentId)) {
            log.error("parent Id is null !");
            throw new BizException("父节点为空！");
        }
        SysOrgan sysOrgan = new SysOrgan();
        sysOrgan.setParentId(parentId);
        return this.findSysOrgan(sysOrgan);
    }

    @Override
    public PageResult<SysOrgan> findSysOrganByPaged(PageRequest<SysOrgan> t) {

        MybatisPageServiceTemplate<SysOrgan, SysOrgan> mybatiesPageServiceTemplate = new MybatisPageServiceTemplate<SysOrgan, SysOrgan>(this.baseMapper) {
            @Override
            protected AbstractWrapper constructWrapper(SysOrgan sysOrgan) {
                LambdaQueryWrapper<SysOrgan> lambdaQueryWrapper = buildSysOrganLambdaQueryWrapper(sysOrgan);
                return lambdaQueryWrapper;
            }
        };

        return mybatiesPageServiceTemplate.doPagingQuery(t);
    }

    private LambdaQueryWrapper<SysOrgan> buildSysOrganLambdaQueryWrapper(SysOrgan sysOrgan) {
        LambdaQueryWrapper<SysOrgan> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (sysOrgan != null) {
            if (StringUtils.isNotBlank(sysOrgan.getName())) {
                lambdaQueryWrapper.
                        like(SysOrgan::getCode, sysOrgan.getName())
                        .or()
                        .like(SysOrgan::getName, sysOrgan.getName());
            }
        }

        return lambdaQueryWrapper;
    }

    @Override
    public List<SysOrgan> findLeafNode() {
        return this.baseMapper.findLeafNode();
    }

    @Override
    public boolean saveOrUpdateOrgan(SysOrgan sysOrgan) {
        SysOrgan po = null;
        if (StringUtils.isNotBlank(sysOrgan.getId())) {
            po = this.getById(sysOrgan.getId());
            if (po == null) {
                logger.error("机构不存在！");
                throw new BizException("机构不存在!");
            }
            if (!po.getCode().equals(sysOrgan.getCode())) {
                logger.error("机构code[{}]已锁定，不允许修改！", sysOrgan.getCode());
                throw new BizException("机构code已锁定，不允许修改！!");
            }
            BeanUtils.copyPropertiesToPartField(sysOrgan, po);
        } else {
            po = sysOrgan;
            List<SysOrgan> sysOrgans = this.findSysOrganByCode(sysOrgan.getCode());
            if (!CollectionUtils.isEmpty(sysOrgans)) {
                logger.error("机构code[{}]已存在！", sysOrgan.getCode());
                throw new BizException("机构code已存在！");
            }
        }
        boolean b = this.saveOrUpdate(po);
        sysOrganUserDao.deleteOrganUser(null, po.getId());
        if (StringUtils.isNotBlank(sysOrgan.getUserId())) {
            Set<String> userIds = Arrays.asList(sysOrgan.getUserId().split(",")).stream().collect(Collectors.toSet());
            if (!CollectionUtils.isEmpty(userIds)) {
                sysOrganUserDao.saveBatchUserIdsAndOrganId(userIds, po.getId());
                /*String organId = po.getId();
                userIds.forEach(userId -> {
                    SysUserOrgan sysUserOrgan = new SysUserOrgan();
                    sysUserOrgan.setUserId(userId);
                    sysUserOrgan.setOrganId(organId);
                    sysUserOrganDao.insert(sysUserOrgan);
                });*/
            }
        }
        sysOrganDeviceDao.deleteOrganDevice(po.getId(), null);
        if (StringUtils.isNotBlank(sysOrgan.getDeviceId())) {
            Set<String> deviceIds = Arrays.asList(sysOrgan.getDeviceId().split(",")).stream().collect(Collectors.toSet());
            if (!CollectionUtils.isEmpty(deviceIds)) {
                sysOrganDeviceDao.saveBatchOrganIdAndDeviceIds(po.getId(), deviceIds);
                /*String organId = po.getId();
                deviceIds.forEach(deviceId -> {
                    SysOrganDevice sysOrganDevice = new SysOrganDevice();
                    sysOrganDevice.setDeviceId(deviceId);
                    sysOrganDevice.setOrganId(organId);
                    sysOrganDeviceDao.insert(sysOrganDevice);
                });*/
            }
        }
        return b;
    }

    private List<SysOrgan> findSysOrganByCode(String code) {
        SysOrgan organ = new SysOrgan();
        organ.setCode(code);
        return this.findSysOrgan(organ);
    }

    @Override
    public List<SysOrgan> findSysOrganByUserId(String userId) {
        return sysOrganUserDao.findOrganByUserId(userId);
    }

    public SysOrgan getOrganFullById(String id) {
        SysOrgan sysOrgan = this.getById(id);
        List<SysDevice> deviceByOrganId = sysOrganDeviceDao.findDeviceByOrganId(id);
        List<SysUser> userByOrganId = sysOrganUserDao.findUserByOrganId(id);
        sysOrgan.setSysDevices(deviceByOrganId);
        sysOrgan.setSysUsers(userByOrganId);
        return sysOrgan;
    }

    @Override
    public boolean deleteById(String id) {
        List<SysOrgan> sysOrganByParentId = this.findSysOrganByParentId(id);
        if (!CollectionUtils.isEmpty(sysOrganByParentId)) {
            logger.error("删除SysOrgan[{}]时,发现已经有[{}]孩子节点", id, sysOrganByParentId.size());
            throw new BizException("请先删除孩子节点!");
        }
        SysOrgan organFullById = this.getOrganFullById(id);
        if (!CollectionUtils.isEmpty(organFullById.getSysDevices())) {
            logger.error("删除SysOrgan[{}]时,发现已经关联SysDevice");
            throw new BizException("请先解除关联的设备信息");
        }
        if (!CollectionUtils.isEmpty(organFullById.getSysUsers())) {
            logger.error("删除SysOrgan[{}]时,发现已经关联SysUser");
            throw new BizException("请先解除关联的用户信息");
        }
        return this.removeById(id);
    }

    @Override
    public void setUserToOrgan(String id, Set<String> userIds) {
        if (!CollectionUtils.isEmpty(userIds)) {
            sysOrganUserDao.deleteOrganUser(null, id);
            sysOrganUserDao.saveBatchUserIdsAndOrganId(userIds, id);
            /*for (String menuId : menuIds) {
            /*for (String menuId : menuIds) {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setRoleId(roleId);
                sysRoleMenu.setMenuId(menuId);
                sysRoleMenuDao.insert(sysRoleMenu);
            }*/
        }
    }

    @Override
    public void setUserToOrgan(String id, List<SysOrganUser> sysOrganUsers) {
        if (!CollectionUtils.isEmpty(sysOrganUsers)) {
            sysOrganUserDao.deleteOrganUser(null, id);
            sysOrganUserDao.saveBatchUsersOrgan(sysOrganUsers, id);
            /*for (String menuId : menuIds) {
            /*for (String menuId : menuIds) {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setRoleId(roleId);
                sysRoleMenu.setMenuId(menuId);
                sysRoleMenuDao.insert(sysRoleMenu);
            }*/
        }
    }

    public List<SysOrgan> getSysOrganByIds(Set<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            logger.error("ids Collection is null or ids Collection size is 0! ");
            throw new BizException("机构id为空！");
        }
        LambdaQueryWrapper<SysOrgan> lambdaQueryWrapper = new LambdaQueryWrapper<SysOrgan>();
        lambdaQueryWrapper.in(SysOrgan::getId, ids);
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public PageResult<SysOrgan> findChildrenNodeByParentId(PageRequest<SysOrgan> t) {
        MybatisPageServiceTemplate<SysOrgan, SysOrgan> mybatisPageServiceTemplate = new MybatisPageServiceTemplate<SysOrgan, SysOrgan>(this.baseMapper) {
            @Override
            protected AbstractWrapper constructWrapper(SysOrgan sysOrgan) {
                return buildSysOrganLambdaQueryWrapper(sysOrgan);
            }

            @Override
            protected String constructNativeSql() {
                return "SELECT * FROM ( SELECT o.* FROM ( SELECT @pId AS pId, ( SELECT @pId := GROUP_CONCAT(id) FROM sys_organ WHERE FIND_IN_SET(parent_Id, @pId)) AS p FROM sys_organ, (SELECT @pId := #{map.pId} ) b WHERE @pId IS NOT NULL ) temp, sys_organ o WHERE FIND_IN_SET(o.parent_Id, temp.pId) AND o.enable_flag = 1) sysOrgan";
            }

            @Override
            public Map constructNativeSqlArgsToMap(SysOrgan sysOrgan) {
                Map<String, String> map = constructMapArgs(sysOrgan);
                return map;
            }
        };
        return mybatisPageServiceTemplate.doPagingQuery(t);
    }

    private String getGenericId(SysOrgan t) {
        String id = "-1";
        if (t != null) {
            id = t.getId();
        }
        return id;
    }

    @Override
    public PageResult<SysOrgan> findParentNodeByParentId(PageRequest<SysOrgan> t) {
        MybatisPageServiceTemplate<SysOrgan, SysOrgan> mybatisPageServiceTemplate = new MybatisPageServiceTemplate<SysOrgan, SysOrgan>(this.baseMapper) {
            @Override
            protected AbstractWrapper constructWrapper(SysOrgan sysOrgan) {
                return buildSysOrganLambdaQueryWrapper(sysOrgan);
            }

            @Override
            protected String constructNativeSql() {
                return "SELECT * FROM ( SELECT o.* FROM ( SELECT @pId AS pId, ( SELECT @pId := parent_id FROM sys_organ WHERE FIND_IN_SET(id, @pId)) AS p FROM sys_organ, ( SELECT @pId := #{map.pId}  ) b WHERE @pId IS NOT NULL ) temp, sys_organ o WHERE FIND_IN_SET(o.id, temp.pId) AND o.enable_flag = 1) sysOrgan";
            }
            @Override
            public Map constructNativeSqlArgsToMap(SysOrgan sysOrgan) {
                Map<String, String> map = constructMapArgs(sysOrgan);
                return map;
            }
        };
        return mybatisPageServiceTemplate.doPagingQuery(t);
    }

    private Map<String, String> constructMapArgs(SysOrgan sysOrgan) {
        Map<String, String> map = new HashMap<>();
        map.put("pId", getGenericId(sysOrgan));
        return map;
    }
}
